#include "Simulator.h"
#include "Arrival/Arrival.h"
#include "Server/Server.h"
#include <QtCore>



Simulator::Simulator(Arrival *arrival, Server* server, double time)
{
    this->end = time;
    this->arrival = arrival;
    this->server = server;
}


SimulationResult Simulator::Run()
{
    double time = 0;
    int queueLength = 0;
    time = time + arrival->Interval();
    QLinkedList<Event> eventList;
    Event nextEvent;
    nextEvent.type = Event::In;
    nextEvent.time = time;
    Event nextArrivalEvent = nextEvent;

    while(time <= end)
    {
        eventList.append(nextEvent);
        switch(nextEvent.type)
        {
        case Event::In:
            nextArrivalEvent.time = nextArrivalEvent.time + arrival->Interval();
            if(time >= server->FreeTime())
                server->Serve(time);
            else
                queueLength++;
            if(server->FreeTime() < nextArrivalEvent.time)
            {
                nextEvent.time = server->FreeTime();
                nextEvent.type = Event::Out;
            }
            else
            {
                nextEvent = nextArrivalEvent;
            }
            //qDebug((QString::number(time) + QString("\tIn")).toStdString().c_str());
            time = nextEvent.time;
            break;
        case Event::Out:

            if(queueLength > 0)
            {
                server->Serve(time);
                queueLength--;
                if(server->FreeTime() < nextArrivalEvent.time)
                {
                    nextEvent.time = server->FreeTime();
                    nextEvent.type = Event::Out;
                }
                else
                {
                    nextEvent = nextArrivalEvent;
                }
            }
            else
            {
                nextEvent = nextArrivalEvent;
            }
            //qDebug((QString::number(time) + QString("\tOut")).toStdString().c_str());
            time = nextEvent.time;

            break;
        }
    }

    return SimulationResult(eventList, this->end);
}

SimulationResult::SimulationResult(QLinkedList<Simulator::Event> &data, double time)
{
    this->data = data;
    this->time = time;
}

double SimulationResult::ELq()
{
    QLinkedListIterator<Simulator::Event> iterator(this->data);
    int queueLength = -1; // -1 means the server are free
    double lastTime = 0;
    QMap<int, double> count;
    while (iterator.hasNext())
    {
        Simulator::Event event = iterator.next();
        if(!count.contains(queueLength))
            count[queueLength] = 0;
        count[queueLength] = count[queueLength] + event.time - lastTime;
        lastTime = event.time;
        switch(event.type)
        {
        case Simulator::Event::In:
            queueLength++;
            break;
        case Simulator::Event::Out:
            queueLength--;
            if(queueLength < -1)
                qDebug()<<"Something wrong:"<<event.time;
            break;
        }
    }
    if(!count.contains(queueLength))
        count[queueLength] = 0;
    count[queueLength] = count[queueLength] + this->time - lastTime;

    QMapIterator<int, double> mapIterator(count);
    double result = 0;
    //qDebug()<<count;
    while(mapIterator.hasNext())
    {
        mapIterator.next();
        if(mapIterator.key() == -1)
            ;//result += 0 * mapIterator.value() / this->time;
        else
            result += mapIterator.key() * mapIterator.value() / this->time;
    }

    return result;
}

double SimulationResult::EWq()
{
    QLinkedListIterator<Simulator::Event> iterator(this->data);
    int queueLength = -1;
    double lastTime = 0;
    int count = 0;
    double result = 0;
    while (iterator.hasNext())
    {
        Simulator::Event event = iterator.next();
        if(queueLength > 0)
            result += queueLength * (event.time - lastTime);
        lastTime = event.time;
        switch(event.type)
        {
        case Simulator::Event::In:
            queueLength++;
            count++;
            break;
        case Simulator::Event::Out:
            queueLength--;
            if(queueLength < -1)
                qDebug()<<"Something wrong:"<<event.time;
            break;
        }
    }
    return result / count;
}
